function StrLen(p: Pchar): longint;
begin
	result := 0;
	if p = nil then
		exit;
	
	while p^ <> #0 do
	begin
		inc(result);
		inc(p);
	end;
end;

function StrDup(a: PChar): PChar;
var l: longint;
begin
	result := nil;
   
   if a = nil then
      exit;
   
	l := strlen(a);
	
	if l <= 0 then
		exit;
	
	result := StrAlloc(l);
	if result <> nil then
		move(a^, result^, l+1);
end;

function StrAlloc(len: longint): Pchar;
begin
	result := nil;
	
	if len <= 0 then
		exit;
	
	result := GetMem(len+1);
	if result <> nil then
		FillChar(result^, len+1, 0);
end;

procedure StrDispose(p: pchar);
begin
	if p = nil then exit;
	
	FreeMem(p);
end;

function StrConcat(a,b: pchar): pchar;
var x,y: longint;
begin
	x := strlen(a);
	y := strlen(b);
	
	result := StrAlloc(x+y);
	
	move(a^, result^, x);
	move(b^, result[x], y);
end;

function StrDelete(a: pchar; idx, len: longint): pchar;
var x: longint;
begin
	result := nil;
	
	if a = nil then exit;
	if len <= 0 then exit;
	
	x := strlen(a);
	
	if idx > x then exit;
	
	if idx+len > x then
		len := x-idx;
	
	if idx = 0 then
	begin
		result := stralloc(x-len);
		move(a[len], result^, x-len);
	end
	else if len+idx = x then
	begin
		result := stralloc(x-len);
		move(a^, result^, idx);
	end
	else
	begin
		result := stralloc(x-len);
		move(a^, result^, idx);
		move(a[len], result[idx], x-len-idx);
	end;
end;

function StrCopy(a: pchar; idx, len: longint): pchar;
var x: longint;
begin
	result := nil;
	
	if a = nil then exit;
	if len <= 0 then
	begin
		result := strdup(a);
		exit;
	end;
	
	x := strlen(a);
	
	if idx > x then exit;
	if idx+len > x then
		len := x-idx;
	
	result := stralloc(len);
	move(a[idx], result^, len);
end;

function StrComp(a,b: pchar; len: longint = -1): boolean;
var c: longint;
begin
	result := false;
	
	c := 0;
	
	if (a = nil) or (b = nil) then exit;
	
	while true do
	begin
		if a^ <> b^ then
			exit;
		if a^ = #0 then
			break;
		inc(c);
		if (c >= len) and (len <> -1) then
			break;
		inc(a);
		inc(b);
	end;
	
	result := true;
end;

function StrPos(sub, a: pchar): longint;
var x,y,i: longint;
begin
	result := -1;
	
	x := strlen(a);
	y := strlen(sub);
	
	for i := 0 to x-y do
	begin
		if strcomp(@a[i], sub,y) then
		begin
			result := i;
			exit;
		end;
	end;
end;

function StrRPos(sub, a: pchar): longint;
var x,y,i: longint;
begin
	result := -1;
	
	x := strlen(a);
	y := strlen(sub);
	
	for i := x-y downto 0 do
	begin
		if strcomp(@a[i], sub,y) then
		begin
			result := i;
			exit;
		end;
	end;
end;

function StrPosChar(sub: char; a: pchar): longint;
var x,i: longint;
begin
	result := -1;
	
	x := strlen(a);
	
	for i := 0 to x-1 do
	begin
		if a[i] = sub then
		begin
			result := i;
			exit;
		end;
	end;
end;

function StrMatch(exp, str: pchar): boolean;
var i, i2, len, len2: longint;
begin
	result := false;
	
	if (exp = nil) or (str = nil) then exit;
	
	i := 0;
	i2 := 0;
	
	len := strlen(exp);
	len2 := strlen(str);
	
	while i < len do
	begin
		if i2 >= len2 then
			exit;
		
		if exp[i] = '*' then
		begin
			inc(i);
		end
		else if exp[i] = '?' then
		begin
			inc(i);
			inc(i2);
		end
		else
		begin
			if exp[i] <> str[i2] then
				exit;
			inc(i);
			inc(i2);
		end;
	end;
	
	result := true;
end;

function IntToStr(int: ptruint): pchar;
var buf: array[0..31] of char;
    i, t: longint;
begin
   if int = 0 then
      result := strdup('0')
   else
   begin
      buf[high(buf)] := #0;
      i := high(buf);
      
      while int > 0 do
      begin
         t := int mod 10;
         int := (int - t) div 10;
         dec(i);
         buf[i] := char(ord('0')+t);
      end;
      result := strdup(@buf[i]);
   end;
end;

function IntToHex(int: ptruint): pchar;
var buf: array[0..31] of char;
    i, t: longint;
begin
   if int = 0 then
      result := strdup('0')
   else
   begin
      buf[high(buf)] := #0;
      i := high(buf);
      
      while int > 0 do
      begin
         t := int mod 16;
         int := (int - t) div 16;
         dec(i);
         if t > 9 then
            buf[i] := char(ord('A')+t-10)
         else
            buf[i] := char(ord('0')+t);
      end;
      result := strdup(@buf[i]);
   end;
end;

function StrFormat(format: pchar; const Args: array of pointer): pchar;
var t, i, pc: longint;
    l, res: pchar;
begin
   t := 0;
   pc := 0;
   
   result := strdup('');
   
   while true do
   begin
      i := StrPosChar('%', @format[t]);
      if i < 0 then
         break;
      
      l := StrCopy(@format[t], 0, i);
      res := StrConcat(result, l); // Concat before
      strdispose(result);
      strdispose(l);
      
      result := res;
      
      case format[t+i+1] of
         'i':
         begin
            l := IntToStr(PPtrUInt(args[pc])^);
            inc(pc);
            res := StrConcat(result, l);
            strdispose(result);
            strdispose(l);
            
            result := res;
         end;
         'x':
         begin
            l := IntToHex(PPtrUInt(args[pc])^);
            inc(pc);
            res := StrConcat(result, l);
            strdispose(result);
            strdispose(l);
            
            result := res;
         end;
         's':
         begin
            res := StrConcat(result, args[pc]);
            inc(pc);
            strdispose(result);
            
            result := res;
         end;
         '%':
         begin
            res := StrConcat(result, '%');
            strdispose(result);
            
            result := res;
         end;
      end;
      
      t := t + i + 2;
   end;
   
   res := StrConcat(result, @format[t]);
   strdispose(result);
   
   result := res;   
end;